#pragma once
#include <type_traits>
#include <iostream>
using std::ostream;

#include "../public/constants.hpp"
#include "../public/exception.hpp"

#include "../container/RBtree.hpp"
#include "../functor/functor_ease_dump.hpp"

namespace bla {
	template<typename _keytype, typename _vtype>
	class map {
	public:
		//merge _keytype and vtype to pair<>
		using totalValue = std::pair<_keytype, _vtype>;
		//using define
		using sizeType = _containerSizeType;
		using differenceType = _containerSizeType;
		using valueType = totalValue;
		using pointerType = totalValue * ;
		using referenceType = totalValue & ;
		using iterator = RBTreeIterator<_keytype, totalValue, _extractFirstOfPairFunctor<_keytype, totalValue>,
			_identitySameTypeCompareFunctor<_keytype>, _sameTypeLessThanCompareFunctor<_keytype>>;
	private:
		RBTree<_keytype, totalValue, _extractFirstOfPairFunctor<_keytype, totalValue>, 
			_identitySameTypeCompareFunctor<_keytype>, _sameTypeLessThanCompareFunctor<_keytype>> _rbt;
	public:
		inline sizeType size() { return _rbt.size(); };
		inline const sizeType size() const { return _rbt.size(); };
		bool find(_keytype v) {
			return _rbt.find(v);
		}
		bool insert(valueType v) {
			return _rbt.insert(v);
		}
		bool remove(_keytype v) {
			return _rbt.remove(v);
		}
		_vtype at(_keytype k) {
			totalValue tv;
			if (_rbt.find(k, tv)) {
				return tv.second;
			}
			else {
				throw baseException("in map template class: in function: at, key not found");
			}
		}
		template<typename _keytype, typename _vtype>
		friend ostream & operator<<(ostream & os, const map<_keytype, _vtype>& li);
	};
	template<typename _keytype, typename _vtype>
	ostream & operator<<(ostream & os, const map<_keytype, _vtype>& m)
	{
		using totalValue = std::pair<_keytype, _vtype>;
		using iterator = RBTreeIterator<_keytype, totalValue, _extractFirstOfPairFunctor<_keytype, totalValue>,
			_identitySameTypeCompareFunctor<_keytype>, _sameTypeLessThanCompareFunctor<_keytype>>;
		iterator iterBegin = m._rbt.begin();
		iterator iterEnd = m._rbt.end();
		for (iterator iter = iterBegin; iter != iterEnd; ++iter) {
			os << (*iter).first << ":" << (*iter).second << " ";
		}

		return os;
	}
}
